#!/usr/bin/env bash
# -*- mode: scheme -*-
exec guile -s $0 $@
!#
(import (rnrs)
        (only (srfi :13 strings)
              string-index
              string-prefix? string-suffix?
              string-concatenate string-trim-both)
        (rnrs io ports)
        (fibers web server)
        (fibers)
        (web request)
        (web response)
        (web uri))

(define (read-file path)
  (with-input-from-file path
    (lambda () (get-bytevector-all (current-input-port)))))

(define (read-file-to-port path port)
  (with-input-from-file path
    (lambda () (let ((bv (get-bytevector-n (current-input-port) (expt 2 20)))) ;; 1MiB
                 (let lp ((count (bytevector-length bv)))
                   (cond ((not (eof-object? count))
                          (put-bytevector port bv 0 count)
                          (lp (get-bytevector-n! (current-input-port) bv 0 count)))
                         (else (close-port port))))))))

(define (handler request body)
  (let* ((path* (uri-path (request-uri request)))
         (path (string-drop path* (min 1 (string-length path*))))
         (port (request-port request))
         ;; test file http://127.0.0.1/htdig/search.html
         (filepath "fileserver.scm")
         (err #f)
         (errparams '())
         (res "")
         (128kiB (expt 2 17))
         (maxsize 128kiB)) ;; 15k threads would be 2GiB
    (if (not (access? filepath R_OK))
        (values (build-response #:code 404)
                (string-append "Resource not found: "
                               filepath))
        (cond ((< (stat:size (stat filepath)) maxsize) ;; can simply read the whole file
               (values '((content-type . (text/html)))
                       (read-file filepath)))
              (else ;; chunk the file to preserve memory
               (spawn-fiber (lambda () (read-file-to-port filepath port))
                            #:parallel? #f)
               (values '((content-type . (text/html)))
                       #f)))))) ;; already putting the body into the port

(run-server handler #:host "192.168.178.101" #:port 4223)
